Skip to content

fix(nemo-relay): bound dependency, migrate intercept API, fix concurrent scopes - #58

Merged
rdasilveiracabral merged 5 commits into
mainfrom
fix-nemo-relay-dependency
Jul 31, 2026
Merged

fix(nemo-relay): bound dependency, migrate intercept API, fix concurrent scopes#58
rdasilveiracabral merged 5 commits into
mainfrom
fix-nemo-relay-dependency

Conversation

@sklinglernv

Copy link
Copy Markdown
Collaborator

nemo-relay was unbounded (>=0.4.0), so fresh installs got 0.6.0 while the lock pinned 0.4.0 — and the intercept contract changed in 0.5, leaving the quickstart broken for anyone installing today.

While verifying, found a second bug: nemo-relay keeps one mutable LIFO scope stack that child asyncio tasks inherit by reference. Overlapping agent calls interleave pushes, the first to finish can't pop, and the run raises RuntimeError out of nemo_flow_scope after already producing its result. Reachable via asyncio.gather(self.a(), self.b()), which our own strategy prompts recommend.

Changes

  • pin nemo-relay>=0.6,<0.7 — 0.7 changes the LLM sanitizer contract with no compat shim
  • migrate intercepts to LLMRequestInterceptOutcome
  • give concurrently-dispatched agent calls their own scope stack; parent linkage kept via scope.push(handle=...); pop failures now log at warning instead of being swallowed
  • 4 concurrency regression tests (the file had none)
  • quickstart cleanup; corrected two comments that were factually wrong

Verification

before after
concurrent run RuntimeError succeeds
scope starts/ends unbalanced balanced
sibling parent_ids collapsed to one distinct

Full suite 6479 passed. Quickstart re-run clean, ATIF inspected.

Note

Scope isolation relies on nemo_relay._scope_stack_var, which is private upstream. Resolved via getattr with graceful degradation, plus a test that fails loudly if it's renamed. Worth raising with the NeMo Relay team — the real ask is a public API for per-task scope isolation.

🤖 Generated with Claude Code

sklinglernv and others added 2 commits July 30, 2026 12:14
…ent scopes

The nemo-relay dependency was unbounded (>=0.4.0), so downstream installs got
0.6.0 while the lock pinned 0.4.0 and CI only ever tested 0.4.0. The intercept
contract changed in 0.5 (LLMRequestInterceptOutcome instead of a tuple), so the
quickstart example was broken for anyone installing today.

Separately, nemo-relay keeps one mutable LIFO scope stack in a ContextVar that
child asyncio tasks inherit by reference. Overlapping agent calls interleaved
their pushes; whichever finished first could not pop, silently desynchronising
the stack, misattributing ATIF ancestry, and raising RuntimeError out of
nemo_flow_scope after the agent had already produced its result. A
concurrently-dispatched call now gets its own scope stack, with parent linkage
preserved via scope.push(handle=...).

- pin nemo-relay>=0.6,<0.7 (0.7 changes the LLM sanitizer contract)
- migrate intercepts to LLMRequestInterceptOutcome
- isolate scope stacks for concurrent agent calls; log pop failures at warning
- add 4 concurrency regression tests (the file had none)
- clean up the quickstart example and correct two false comments

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The upstream package was renamed nemo_flow -> nemo_relay some time ago, but
nooa's own API kept the old prefix and the module aliased the import back to
`nemo_flow`. Cleaning up the quickstart made the split visible: the example
referred to `nemo_relay` for the upstream package while still importing
`nemo_flow_scope` from nooa.

BREAKING CHANGE: no compatibility aliases are provided.

  nooa.nemo_flow_middleware      -> nooa.nemo_relay_middleware
  nemo_flow_scope                -> nemo_relay_scope
  install_nemo_flow              -> install_nemo_relay
  nemo_flow_llm_middleware       -> nemo_relay_llm_middleware
  nemo_flow_tool_middleware      -> nemo_relay_tool_middleware
  nemo_flow_agent_call_middleware-> nemo_relay_agent_call_middleware

Also drops the now-meaningless rename-era comments and the `import nemo_relay
as nemo_flow` alias, and renames the two test modules to match.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sklinglernv and others added 3 commits July 31, 2026 09:25
…oject

The first pass matched only snake_case (\bnemo_flow\b) and was scoped to
*.py/*.md under src/tests/examples/skills, so it missed:

- 11 CamelCase test classes (TestNemoFlow* -> TestNemoRelay*)
- two .gitignore comments (file type not searched)
- the pyproject extra's header, including a now-obsolete note that the
  upstream package "was renamed from nemo-flow to nemo-relay"

Verified with an unfiltered `git grep -inE "nemo[-_ ]?flow"` over all tracked
files: zero matches. Remaining occurrences of "flow" are ordinary English
(event flow, control flow, OAuth flow).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
refactor(nemo-relay)!: rename nemo_flow_* to nemo_relay_*
@rdasilveiracabral
rdasilveiracabral merged commit ffaa092 into main Jul 31, 2026
5 checks passed
@rdasilveiracabral
rdasilveiracabral deleted the fix-nemo-relay-dependency branch July 31, 2026 23:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants